#include "QPcap.h"


QPcap::QPcap(int refreshInterval, QObject *parent) : QThread(parent){
    this -> interfaces = QPcap::getAllInterfaces();
    this -> selectedInterface = 1;
    this -> refreshInterval = refreshInterval;
    this -> portsRestrict = new QList<int*>();
    this -> protocolsRestrict = new QList<int>();
    this -> souldStopCapturing = false;
}


QPcap::~QPcap(){
    pcap_freealldevs(this -> interfaces);

    while (!this -> portsRestrict -> isEmpty()){
        free(this -> portsRestrict -> first());
        this -> portsRestrict -> pop_front();
    }

    delete this -> portsRestrict;
    delete this -> protocolsRestrict;
}


void QPcap::run(){
    this -> souldStopCapturing = false;
    openInterface();
}

void QPcap::stop(){
    this -> souldStopCapturing = true;
    pcap_breakloop(this -> handle);
    if (!this -> wait(100)){
        this->terminate();
    }
    qDebug() << "Listening stopped";
}


void QPcap::setRefreshInterval(int time){
    this -> refreshInterval = time;
}



void QPcap::addingPortRestrict(int port){
    addingPortRestrictRange(port, port);
}

void QPcap::addingPortRestrictRange(int min, int max){
    int * newRange = (int *) malloc(sizeof(int) * 2);
    newRange[0] = min;
    newRange[1] = max;
    this -> portsRestrict -> append(newRange);
}




QString QPcap::getActiveInterfaceName(){
    QList<pcap_if_t *> interfaceList = getInterfacesList();
    return QString(interfaceList.at(this -> selectedInterface - 1) -> description);
}

bool QPcap::isPortIntoRestrict(int port){
    if (this -> portsRestrict -> isEmpty())
        return true;
    for (int i = 0; i < this -> portsRestrict -> size(); i++){
        if (this -> portsRestrict -> at(i)[0] <= port && this -> portsRestrict -> at(i)[1] >= port)
            return true;
    }
    return false;
}


void QPcap::selectInterface(int selectedInterface){
    this -> selectedInterface = selectedInterface;
}



pcap_if_t * QPcap::getAllInterfaces(){
    pcap_if_t * alldevs;
    char errbuf[PCAP_ERRBUF_SIZE];
        /* Retrieve the device list on the local machine */
        if (pcap_findalldevs_ex((char*)PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1){
            qDebug() << "Error in pcap_findalldevs: " + QString(errbuf) + "\n";
        }
    return alldevs;
    }



pcap_if_t * QPcap::getInterfaces(){
    return this -> interfaces;
}





int QPcap::getIndexFromInterfaceName(QString name){
    QList<pcap_if_t *> interfaceList = getInterfacesList();
    for (int i = 0; i < interfaceList.length(); i++){
        if (QString(interfaceList.at(i) -> name) == QString(name))
            return i;
    }
    return -1;
}


QString QPcap::getNameFromInterfaceIndex(int index){
    QList<pcap_if_t *> interfaceList = getInterfacesList();
    for (int i = 0; i < interfaceList.length(); i++){
       if (i == index)
           return QString(interfaceList.at(i)->name);
    }
    return QString();
}




QList<pcap_if_t*> QPcap::getInterfacesList(){
    pcap_if_t * d;
    QList<pcap_if_t*> list = QList<pcap_if_t*>();
    for(d = this -> interfaces; d; d=d->next){
        list.append(d);
    }
    return list;
}



void QPcap::openInterface(){
    pcap_if_t * d;
    int i=0;
    char errbuf[PCAP_ERRBUF_SIZE];

    /* Jump to the selected adapter */
       for(d = this -> interfaces, i=0; i< this -> selectedInterface - 1 ;d=d->next, i++);
       /* Open the device */
       if ( (this -> handle = pcap_open(d->name,   // name of the device
                                 65536,            // portion of the packet to capture
                                                   // 65536 guarantees that the whole packet will be captured on all the link layers
                                 PCAP_OPENFLAG_PROMISCUOUS,    // promiscuous mode
                                 this -> refreshInterval,      // read timeout
                                 NULL,             // authentification on the remote machine
                                 errbuf            // error buffer
                                 ) ) == NULL)
       {
           qDebug() << "\nUnable to open the adapter. " + QString(d->name) + "is not supported by WinPcap\n";
           stop();
       }
    qDebug() << "listening on " + QString(d->description) + "...";
    readPackets();
}





void QPcap::readPackets(){
    struct pcap_pkthdr packetHeader;
    const u_char * data;
    QPcapPacket * newPacket;
    while (true){
        while ((data = pcap_next(this -> handle, &packetHeader))!= NULL){
            if (this -> souldStopCapturing)
                return;
            newPacket = new QPcapPacket((unsigned char *) data);
            if (isProtocolIntoRestrict(newPacket -> getProtocol()) && (isPortIntoRestrict(newPacket->getDestinationPort()) || isPortIntoRestrict(newPacket->getSourcePort())))
                emit signalNewPacket(newPacket);
            else
                delete newPacket;
        }
        this -> msleep(this -> refreshInterval);
    }
}



void QPcap::addingProtocolRestrict(int protocol){
    this -> protocolsRestrict -> append(protocol);
}


bool QPcap::isProtocolIntoRestrict(int protocol){
    if ( this -> protocolsRestrict -> isEmpty())
        return true;
    for (int i = 0; i <  this -> protocolsRestrict -> length(); i++){
        if (protocol ==  this -> protocolsRestrict -> at(i))
            return true;
    }
    return false;
}



